
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include "../luaParameters.h"
#include "../global.h"
#include <iostream>
#include <boost/filesystem.hpp>
#include <log/log.h>
#include <appendix/phy_constants.h>
#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <boost/regex.hpp>
#include <thread>
#include <boost/thread/mutex.hpp>
#include <iostream>

#include<iomanip>


namespace lua{
	static luaParameters globalP;


	luaPoint2DdExpression::luaPoint2DdExpression()
	:m_value()
	 {
	 }

	luaPoint2DdExpression::luaPoint2DdExpression(const std::string& expr1,const std::string& expr2)
	{
		set_expression(expr1,expr2);
	}

	void luaPoint2DdExpression::set_parameters(std::shared_ptr<lua::luaParameters> p)
	{
		luaExpression::set_parameters(p);
		for( int ii=0; ii < 2; ii++)
			m_exprs[ii].set_parameters(p);
	}


	void luaPoint2DdExpression::set_expression(const std::string& expr1,const std::string& expr2)
	{
		set_expression_impl(expr1,0);
		set_expression_impl(expr2,1);
	}
	void luaPoint2DdExpression::set_expression(double expr1,double expr2)
	{
		set_expression((boost::format("%1$.16g") % expr1).str(),
					   (boost::format("%1$.16g") % expr2).str());
	}

	void luaPoint2DdExpression::set_expression(const luaDoubleExpression& expr1,const luaDoubleExpression& expr2)
	{
		m_exprs[0] = expr1;
		m_exprs[1] = expr2;
		m_exprs[0].set_parameters(m_parameters);
		m_exprs[1].set_parameters(m_parameters);
		m_value[0] = m_exprs[0]();
		m_value[1] = m_exprs[1]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}


	void luaPoint2DdExpression::set_expression(const luaDoubleExpression& expr, int idx)
	{
		m_exprs[idx] = expr;
		m_exprs[idx].set_parameters(m_parameters);
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}


	void luaPoint2DdExpression::set_expression_impl(const std::string& expr,int idx)
	{
		m_exprs[idx].set_expression(expr);
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}

	void luaPoint2DdExpression::build() const
	{
		build_impl(0);
		build_impl(1);
	}

	void luaPoint2DdExpression::build_impl(int idx) const
	{
		m_exprs[idx].build();
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}
	void luaPoint2DdExpression::set_valid() const
	{
		if(m_exprs[0].valid() && m_exprs[1].valid())
			m_bValid = true;
		else
			m_bValid = false;
	}

	void luaPoint2DdExpression::set_need_evaluate() const
	{
		if(m_exprs[0].need_evaluate() || m_exprs[1].need_evaluate())
			m_bNeedEvaluate = true;
		else
			m_bNeedEvaluate = false;
	}

	void luaPoint2DdExpression::set_synatex_error() const
	{
		if(m_exprs[0].synatex_error() || m_exprs[1].synatex_error())
			m_bSynatexError = true;
		else
			m_bSynatexError = false;
	}


	Point2Dd luaPoint2DdExpression::operator()(void) const
	{
		if(!m_bNeedEvaluate) return m_value;
		build();
		return m_value;
	}
	Point2Dd luaPoint2DdExpression::operator()(bool& ok) const
	{
		ok = false;
		if(m_bSynatexError){
			return m_value;
		}
		if(!m_bNeedEvaluate){
			ok = true;
			return m_value;
		}
		build();
		if( m_bValid ) ok = true;
		return m_value;
	}

	bool luaPoint2DdExpression::valuate(Point2Dd& v) const
	{
		bool ok;
		v = (*this)(ok);
		return ok;
	}



	bool luaPoint2DdExpression::operator==(const luaPoint2DdExpression& rhs) const
	{
		if( m_exprs != rhs.m_exprs ) return false;
		if( m_parameters != rhs.m_parameters ) return false;
		return true;
	}
	bool luaPoint2DdExpression::operator!=(const luaPoint2DdExpression& rhs) const
	{
		return !operator==(rhs);
	}


	luaPoint3DdExpression::luaPoint3DdExpression()
	:m_value()
	 {
	 }

	luaPoint3DdExpression::luaPoint3DdExpression(const std::string& expr1,
												 const std::string& expr2,
												 const std::string& expr3)
	{
		set_expression(expr1,expr2,expr3);
	}
	luaPoint3DdExpression::luaPoint3DdExpression(double expr1,
												 double expr2,
												 double expr3)
	{
		set_expression(expr1,expr2,expr3);
	}

	void luaPoint3DdExpression::set_parameters(std::shared_ptr<lua::luaParameters> p)
	{
		luaExpression::set_parameters(p);
		for( int ii=0; ii < 3; ii++)
			m_exprs[ii].set_parameters(p);
	}

	void luaPoint3DdExpression::set_expression(const std::string& expr1,const std::string& expr2,const std::string& expr3)
	{
		set_expression_impl(expr1,0);
		set_expression_impl(expr2,1);
		set_expression_impl(expr3,2);
	}

	void luaPoint3DdExpression::set_expression(double expr1,double expr2,double expr3)
	{
		set_expression((boost::format("%1$.16g") % expr1).str(),
					   (boost::format("%1$.16g") % expr2).str(),
					   (boost::format("%1$.16g") % expr3).str());
	}

	void luaPoint3DdExpression::set_expression(const luaDoubleExpression& expr1,
												const luaDoubleExpression& expr2,
												const luaDoubleExpression& expr3)
	{
		m_exprs[0] = expr1;
		m_exprs[1] = expr2;
		m_exprs[2] = expr3;
		m_exprs[0].set_parameters(m_parameters);
		m_exprs[1].set_parameters(m_parameters);
		m_exprs[2].set_parameters(m_parameters);
		m_value[0] = m_exprs[0]();
		m_value[1] = m_exprs[1]();
		m_value[2] = m_exprs[2]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}


	void luaPoint3DdExpression::set_expression(const luaDoubleExpression& expr, int idx)
	{
		m_exprs[idx] = expr;
		m_exprs[idx].set_parameters(m_parameters);
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}

	void luaPoint3DdExpression::set_expression(double val, int idx){
		set_expression( std::to_string(val),idx);
	}



	void luaPoint3DdExpression::set_expression_impl(const std::string& expr,int idx)
	{
		m_exprs[idx].set_expression(expr);
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}

	void luaPoint3DdExpression::build() const
	{
		build_impl(0);
		build_impl(1);
		build_impl(2);
	}

	void luaPoint3DdExpression::build_impl(int idx) const
	{
		m_exprs[idx].build();
		m_value[idx] = m_exprs[idx]();
		set_need_evaluate();
		set_valid();
		set_synatex_error();
	}

	void luaPoint3DdExpression::set_valid() const
	{
		if(m_exprs[0].valid() && m_exprs[1].valid() && m_exprs[2].valid())
			m_bValid = true;
		else
			m_bValid = false;
	}

	void luaPoint3DdExpression::set_need_evaluate() const
	{
		if(m_exprs[0].need_evaluate() || m_exprs[1].need_evaluate() || m_exprs[2].need_evaluate())
			m_bNeedEvaluate = true;
		else
			m_bNeedEvaluate = false;
	}

	void luaPoint3DdExpression::set_synatex_error() const
	{
		if(m_exprs[0].synatex_error() || m_exprs[1].synatex_error() || m_exprs[2].synatex_error())
			m_bSynatexError = true;
		else
			m_bSynatexError = false;
	}

	Point3Dd luaPoint3DdExpression::operator()(void) const
	{
		if(!m_bNeedEvaluate) return m_value;
		build();
		return m_value;
	}

	Point3Dd luaPoint3DdExpression::operator()(bool& ok) const
	{
		ok = false;
		if(m_bSynatexError){
			return m_value;
		}
		if(!m_bNeedEvaluate){
			ok = true;
			return m_value;
		}
		build();
		if( m_bValid ) ok = true;
		return m_value;
	}

	bool luaPoint3DdExpression::valuate(Point3Dd& v) const
	{
		bool ok;
		v = (*this)(ok);
		return ok;
	}

	bool luaPoint3DdExpression::valuate(std::array<double,3>& v) const
	{
		bool ok;
		auto vpt = (*this)(ok);
		for(int ii=0; ii < 3; ii++ ) v[ii] = vpt[ii];
		return ok;
	}

	bool luaPoint3DdExpression::valuate(std::vector<double>& v) const
	{
		bool ok;
		auto vpt = (*this)(ok);
		if(v.size()!=3) v.resize(3);
		for(int ii=0; ii < 3; ii++ ) v[ii] = vpt[ii];
		return ok;
	}


	bool luaPoint3DdExpression::operator==(const luaPoint3DdExpression& rhs) const
	{
		if( m_exprs != rhs.m_exprs ) return false;
		if( m_parameters != rhs.m_parameters ) return false;
		return true;
	}

	bool luaPoint3DdExpression::operator!=(const luaPoint3DdExpression& rhs) const
	{
		return !operator==(rhs);
	}

};


